#include "TPlaca.h"

int Placa_Crear(TPlaca* placa, TDireccion dir) {
	if ((dir > DIR_MIN) && (dir < DIR_MAX)) {
		placa->mensaje = NULL;
		placa->direccion = dir;
		placa->buffer_lleno = 0;
		placa->mux = NULL;

		return PLACA_OK;
	}
	else {
		return PLACA_ERR_RANGO;
	}
}

int Placa_Destruir(TPlaca* placa){
/*	if (placa->mensaje != NULL) {
		Mensaje_Destruir(placa->mensaje);
		free(placa->mensaje);
	}*/

	return PLACA_OK;
}

TDireccion Placa_GetDireccion(TPlaca* placa) {
	return (placa->direccion);
}

int Placa_Recibir(TPlaca* placa, void* mensaje, size_t tam) {
	int codigo_error;
	TDireccion destino;
	char* texto;

	texto = malloc(tam + 1);
	Mensaje_ObtenerTexto(mensaje, &texto);

	if (strlen(texto) > MTU) {
		free(texto);
		return PLACA_ERR_OVERFLOW;
	}

	Mensaje_ObtenerDireccion(mensaje, &destino);

	if ((destino == placa->direccion) || (destino == DIR_BROADCAST)) {
		if (placa->mux) {
			codigo_error = Mux_Recibir(placa->mux, mensaje, tam);
			if (codigo_error) {
			    switch (codigo_error){
                    case 3: {
                        free(texto);
                        return PLACA_ERR_MEDIOTRANSMITIR;
                        break;
                    }
                    default:
                    free(texto);
                    return PLACA_ERR_INESPERADO;
				/* TODO: Manejar salida */
			    }
			}
			else {
                free(texto);
				return PLACA_OK;
			}
		}
		else {
			placa->mensaje = malloc(tam);
			strcpy(placa->mensaje, texto);
			placa->buffer_lleno = 1;
			free(texto);
			return PLACA_OK;
		}
	}
	else {
	free(texto);
		return PLACA_OK;
	}
}

int Placa_Enviar(TPlaca* placa, void* mensaje, size_t tam, TDireccion destino) {
	int codigo_error;

	codigo_error = Medio_Transmitir(placa->medio, mensaje, tam);

	if (codigo_error) {
		switch (codigo_error) {
			case 99:
				return PLACA_ERR_MEDIOTRANSMITIR;
			default:
				return PLACA_ERR_INESPERADO;
		}
	}
	else {
		return PLACA_OK;
	}
}

/* No se usa ya que la placa siempre va a tener un Mux conectado */
size_t Placa_Leer(TPlaca* placa, void* destino) {
  if (placa->buffer_lleno) {
      strcpy((char*)destino, (char*)placa->mensaje);
      free(placa->mensaje);
      placa->buffer_lleno = 0;
      return (size_t) strlen(destino);
  }
  else {
      return PLACA_BUFFER_VACIO;
  }
}

int Placa_Conectar(TPlaca* placa, TMedio* medio) {
    int codigo_error;
    placa->medio = medio;

    codigo_error = Medio_Conectar(placa->medio,placa);
    if (codigo_error) {
    	return PLACA_ERR_MEDIOCONECTAR;
    }
    else {
    	return PLACA_OK;
    }
}

int Placa_Desconectar(TPlaca* placa) {
	return Medio_Desconectar(placa->medio, placa);
}

int Placa_ConectarMux(TPlaca* placa, TMux* mux) {
	int salida;

	if (placa->mux != NULL) {
		return PLACA_ERR_MUXYACONECTADO;
	}

	salida = Mux_Conectar(mux, placa);
	if (!salida) {

	    #ifdef __DEBUG__
        printf("Placa_ConectarMux:\n Direccion mux = %x\n",mux);
        #endif

		placa->mux = mux;
		return PLACA_OK;
	}
	else {
		switch (salida) {
			case MUX_ERR_PLACACONECTADA:
				return PLACA_ERR_MUXYATIENEPLACA;
			default:
				return PLACA_ERR_INESPERADO;
		}
	}
}

int Placa_DesconectarMux(TPlaca* placa) {
	Mux_Destruir(placa->mux);
	placa->mux = NULL;
	return PLACA_OK;
}
